package com.tzm.gaflow.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import com.tzm.gaflow.consts.FlowNames;
import com.tzm.gaflow.dto.GaFlowDTO;
import com.tzm.gaflow.entity.GaFlowGrant;
import com.tzm.gaflow.entity.GaFlowInfo;
import com.tzm.gaflow.entity.GaFlowMain;
import com.tzm.gaflow.service.GaFlowManagerService;
import com.tzm.gaflow.vo.GaFlowInfoVO;
import com.tzm.gaflow.web.exception.BusinessException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class GaFlowManagerServiceImpl implements GaFlowManagerService {

    @Override
    public List<GaFlowInfoVO> listFlowByBussinesType(String bussinesType) {
        List<GaFlowInfo> gaFlowInfos = new GaFlowInfo()
                .selectList(Wrappers.<GaFlowInfo>lambdaQuery()
                        .eq(GaFlowInfo::getBussinesType, bussinesType)
                        .eq(GaFlowInfo::getActive, FlowNames.FLOW_ACTIVE)
                        .orderByAsc(GaFlowInfo::getFlowSel));
        if (!CollUtil.isEmpty(gaFlowInfos)) {
            List<String> flowIds = gaFlowInfos.stream().map(GaFlowInfo::getFlowId).collect(Collectors.toList());
            List<GaFlowGrant> gaFlowGrants = new GaFlowGrant()
                    .selectList(Wrappers.<GaFlowGrant>lambdaQuery()
                            .in(GaFlowGrant::getFlowId, flowIds));
            Map<String, List<GaFlowGrant>> gaFlowGrantGroup = gaFlowGrants.stream().collect(Collectors.groupingBy(GaFlowGrant::getFlowId));
            List<GaFlowInfoVO> gaFlowInfoVOList = gaFlowInfos.stream().map(gaFlowInfo -> {
                GaFlowInfoVO gaFlowInfoVO = new GaFlowInfoVO();
                BeanUtil.copyProperties(gaFlowInfo, gaFlowInfoVO);
                gaFlowInfoVO.setGaFlowGrants(gaFlowGrantGroup.get(gaFlowInfo.getFlowId()));
                return gaFlowInfoVO;
            }).collect(Collectors.toList());
            return gaFlowInfoVOList;
        } else {
            List<GaFlowInfoVO> gaFlowInfoVOList = new ArrayList<>();
            return gaFlowInfoVOList;
        }

    }

    @Override
    public void saveFlow(GaFlowDTO gaFlowDTO) {
        if (ObjectUtil.isNull(gaFlowDTO)) {
            throw new BusinessException("传入的流程信息不能为空!");
        }
        if (StrUtil.isBlank(gaFlowDTO.getBussinesType())) {
            throw new BusinessException("传入的业务类型不能为空!");
        }
        // if run
        if (checkIfRun(gaFlowDTO.getBussinesType())) {
            throw new BusinessException("业务类型【" + gaFlowDTO.getBussinesType() + "】有未完成的流程，不能编辑修改!");
        }
        List<GaFlowInfo> gaFlowInfoList = this.getFlowInfoListByBussinesType(gaFlowDTO.getBussinesType());
        //INVALID flow
        gaFlowInfoList.forEach(gaFlowInfo -> {
            gaFlowInfo.setActive(FlowNames.FLOW_INVALID);
            gaFlowInfo.updateById();
            //delete Grants
            new GaFlowGrant().delete(Wrappers.<GaFlowGrant>lambdaQuery()
                    .eq(GaFlowGrant::getFlowId, gaFlowInfo.getFlowId()));
        });

        for (int i = 0; i < gaFlowDTO.getGaFlowInfos().size(); i++) {
            // new flowId
            gaFlowDTO.getGaFlowInfos().get(i).setFlowId(IdUtil.simpleUUID());
            gaFlowDTO.getGaFlowInfos().get(i).setBussinesType(gaFlowDTO.getBussinesType());
            gaFlowDTO.getGaFlowInfos().get(i).setRefuseRule("1");
            gaFlowDTO.getGaFlowInfos().get(i).setAssignRule("1");
            if (i == 0) {
                gaFlowDTO.getGaFlowInfos().get(i).setPreviousFlowId("");
                gaFlowDTO.getGaFlowInfos().get(i).setPreviousFlowName("");
                //set flow_sel
                gaFlowDTO.getGaFlowInfos().get(i).setFlowSel(Convert.toLong(i));
                gaFlowDTO.getGaFlowInfos().get(i).setActive(FlowNames.FLOW_ACTIVE);
            } else {
                gaFlowDTO.getGaFlowInfos().get(i - 1).setNextFlowId(gaFlowDTO.getGaFlowInfos().get(i).getFlowId());
                gaFlowDTO.getGaFlowInfos().get(i - 1).setNextFlowName(gaFlowDTO.getGaFlowInfos().get(i).getFlowName());
                gaFlowDTO.getGaFlowInfos().get(i - 1).updateById();
                //set flow_sel + 1
                gaFlowDTO.getGaFlowInfos().get(i).setFlowSel(Convert.toLong(i));
                gaFlowDTO.getGaFlowInfos().get(i).setActive(FlowNames.FLOW_ACTIVE);
            }
            if (i != gaFlowDTO.getGaFlowInfos().size() - 1) {
                gaFlowDTO.getGaFlowInfos().get(i + 1).setPreviousFlowId(gaFlowDTO.getGaFlowInfos().get(i).getFlowId());
                gaFlowDTO.getGaFlowInfos().get(i + 1).setPreviousFlowName(gaFlowDTO.getGaFlowInfos().get(i).getFlowName());
            }
            gaFlowDTO.getGaFlowInfos().get(gaFlowDTO.getGaFlowInfos().size() - 1).setNextFlowId("");
            gaFlowDTO.getGaFlowInfos().get(gaFlowDTO.getGaFlowInfos().size() - 1).setNextFlowName("");

            gaFlowDTO.getGaFlowInfos().get(i).insert();
            String flowId = gaFlowDTO.getGaFlowInfos().get(i).getFlowId();
            //Grants
            gaFlowDTO.getGaFlowInfos().get(i).getGaFlowGrants().forEach(gaFlowGrant -> {
                gaFlowGrant.setFlowId(flowId);
                gaFlowGrant.insert();
            });
        }

    }

    private List<GaFlowInfo> getFlowInfoListByBussinesType(String bussinesType) {
        List<GaFlowInfo> gaFlowInfoList = new GaFlowInfo().selectList(Wrappers.<GaFlowInfo>lambdaQuery()
                .eq(GaFlowInfo::getBussinesType, bussinesType)
                .eq(GaFlowInfo::getActive, FlowNames.FLOW_ACTIVE));
        return gaFlowInfoList;
    }

    private boolean checkIfRun(String bussinesType) {
        Integer integer = new GaFlowMain()
                .selectCount(Wrappers.<GaFlowMain>lambdaQuery()
                        .eq(GaFlowMain::getBussinesType, bussinesType)
                        .ne(GaFlowMain::getTaskState, FlowNames.TASKSTATE_END));
        return integer > 0 ? true : false;
    }

    @Override
    public List<GaFlowGrant> listGrantByFlowId(String flowId) {
        List<GaFlowGrant> gaFlowGrants = new GaFlowGrant()
                .selectList(Wrappers.<GaFlowGrant>lambdaQuery()
                        .eq(GaFlowGrant::getFlowId, flowId));
        return gaFlowGrants;
    }


}
